package controller

import (
	"admin-server/libs"
	"admin-server/models"
	"fmt"
	"github.com/gin-gonic/gin"
	"reflect"
	"strings"
)

type ArticleItem struct {
	ID        uint             `json:"id"`
	CateId    uint             `json:"cate_id"`
	Title     string          `json:"title"`
	Subtitle  string          `json:"subtitle"`
	Keyword   string          `json:"keyword"`
	Content   string          `json:"content"`
	ViewCount int             `json:"view_count"`
	Cate      ArticleCateItem `json:"cate" gorm:"foreignkey:ID;references:CateId"`
}

type ArticleCateItem struct {
	ID   uint    `json:"id"`
	Name string `json:"name"`
}

// 获取文章列表
func GetArticleList(ctx *gin.Context) {
	var (
		list []models.Article
		res []ArticleItem
	)

	libs.GetDb().
		Select("id,cate_id,title,subtitle,keyword,view_count,created_at").
		Order("created_at DESC").
		Preload("Cate").
		Find(&list)

	fmt.Printf("%d\n", len(list))
	structClone(&list, &res)

	ctx.JSON(200, gin.H{
		"res": res,
	})
}

func structClone(a interface{}, b interface{}) {
	src := reflect.ValueOf(a)
	dist := reflect.ValueOf(b)
	table2type := getFieldType(reflect.TypeOf(b))

	if src.Kind() == reflect.Ptr {
		src = src.Elem()
	}
	if dist.Kind() == reflect.Ptr {
		dist = dist.Elem()
	}

	switch src.Kind() {
	case reflect.Array, reflect.Slice:
		dist.Set(reflect.MakeSlice(dist.Type(), src.Len(), 20))

		fmt.Printf("type:%v\n", dist.Type())
		fmt.Printf("%v\n", dist)

		fmt.Printf("yum_count:%v\n", src.Len())
		fmt.Printf("%v", src.Kind())
		for i := 0; i < src.Len(); i++ {
			src := src.Index(i)
			dst := reflect.New(table2type)

			for n := 0; n < table2type.NumField(); n++ {
				field := dst.Elem().Field(n)
				field.Set(typeValue(src, dst, n))
			}
			dist.Index(i).Set(dst.Elem())
		}

		fmt.Println()

		break
	case reflect.Struct:
		fmt.Printf("\nsrc_type:%v\n", src.Type())
		fmt.Printf("\ndist_type:%v\n", dist.Type())

		fmt.Printf("src_count:%v\n", src.NumField())

		fmt.Printf("%v\n", src)
		fmt.Printf("%v\n", dist)
		fmt.Printf("%v\n", table2type.NumField())
		fmt.Println()

		dst := reflect.New(table2type)

		for n := 0; n < table2type.NumField(); n++ {
			field := dst.Elem().Field(n)
			typeElem := dst.Type().Elem()

			val := src.FieldByName(typeElem.Field(n).Name)
			fmt.Printf("aaaaaaaa:%v\n", val)
			field.Set(val)
		}
		fmt.Printf("result: %v\n", dst)
		// dist.Set(dst.Elem())

		//
		//for n := 0; n < table2type.NumField(); n++ {
		//	field := immutable2.Field(n)
		//	typeElem := immutable2.Type().Elem()
		//
		//	val := immutable.FieldByName(typeElem.Field(n).Name)
		//	fmt.Printf("%s: %v\n", typeElem.Field(n).Type, val)
		//	field.Set(val)
		//}
		break
	default:
		break
	}

	// fmt.Println(b)
}

func typeValue(src reflect.Value, dst reflect.Value, n int) reflect.Value {
	typeElem := dst.Type().Elem()
	f := typeElem.Field(n)
	val := src.FieldByName(f.Name)

	typeStr := f.Type.Name()
	if strings.Index(typeStr, "int") > -1 || strings.Index(typeStr, "str") > -1 {
		return val
	} else {
		fmt.Printf("f:type: %v\n", typeElem.Field(n).Type)
		structClone(val.Interface(), &newVal)
		val = reflect.ValueOf(newVal)
		// fmt.Printf("%v: %v\n", src, val)
	}

	return val
}

// 获得struct的反射类型
func getFieldType(t reflect.Type) reflect.Type {
	kind := t.Kind()
	if kind == reflect.Ptr || kind == reflect.Array || kind == reflect.Slice {
		return getFieldType(t.Elem())
	}
	return t
}
//
//func readTag(f reflect.StructField, tag string) (string, int) {
//	const flagIgnore = 1 << iota
//	val, ok := f.Tag.Lookup(tag)
//	fieldTag := ""
//	flag := 0
//	if !ok {
//		flag |= flagIgnore
//		return "", flag
//	}
//	opts := strings.Split(val, ",")
//
//
//}